/*
*Copyright 2021-2023 NERCIS
*
*Licensed under the Apache License, Version 2.0 (the "License");
*you may not use this file except in compliance with the License.
*You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*Unless required by applicable law or agreed to in writing, software
*distributed under the License is distributed on an "AS IS" BASIS,
*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*See the License for the specific language governing permissions and
*limitations under the License.
*/

package cn.ac.nercis.pes.community.utils;

import cn.ac.nercis.pes.common.constant.common.BaseConstants;
import cn.ac.nercis.pes.common.constant.project.FinishState;
import cn.ac.nercis.pes.community.constant.AppConstants;
import cn.ac.nercis.pes.community.controller.dialog.ScoreInfoController;
import cn.ac.nercis.pes.community.model.dto.SizeDTO;
import cn.ac.nercis.pes.community.support.event.CommonCallback;
import cn.ac.nercis.pes.community.views.dialog.ScoreInfoView;
import javafx.geometry.Orientation;
import javafx.scene.control.Label;
import javafx.scene.control.Separator;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseButton;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.springframework.core.io.ClassPathResource;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 控件辅助类
 * @author zpy
 * @version 1.0.0
 */
public final class ControlUtils {
    private final static String TOOLTIP_FORMAT = "%s(%s)";
    public final static Integer DOUBLE_CLICK_COUNT = 2;
    private final static String FILE_SPLIT = "/";
    private final static Integer EVALUATION_WIN_TITLE_MAX_LENGTH = 35;

    private ControlUtils(){}

    public static void setLabelTextByLimit(Label label,String text,int maxLength){
        if(StringUtils.length(text) > maxLength){
            label.setText(StringUtils.substring(text,0,maxLength).concat("..."));
            label.setTooltip(new Tooltip(text));
        }else{
            label.setText(text);
        }
    }

    public static String getTextByLimit(String text, int maxLength){
        if(StringUtils.length(text) > maxLength){
            return StringUtils.substring(text,0,maxLength).concat("...");
        }else{
            return text;
        }
    }

    public static void initUnitTargetListViewState(Label menuLabel, FinishState state){
        switch (state) {
            case INCOMPLETE -> {
                menuLabel.setGraphic(IconUtils.getGlyph("incomplete-process-icon"));
                menuLabel.getStyleClass().add("incomplete-process");
                if (Objects.nonNull(menuLabel.getTooltip())) {
                    menuLabel.getTooltip().setText(String.format(TOOLTIP_FORMAT, menuLabel.getTooltip().getText(),
                            "未完成"));
                } else {
                    menuLabel.setTooltip(new Tooltip(String.format(TOOLTIP_FORMAT, menuLabel.getText(),
                            "未完成")));
                }
            }
            case FINISH -> {
                menuLabel.setGraphic(IconUtils.getGlyph("finish-process-icon"));
                menuLabel.getStyleClass().add("finish-process");
                if (Objects.nonNull(menuLabel.getTooltip())) {
                    menuLabel.getTooltip().setText(String.format(TOOLTIP_FORMAT, menuLabel.getTooltip().getText(),
                            "已完成"));
                } else {
                    menuLabel.setTooltip(new Tooltip(String.format(TOOLTIP_FORMAT, menuLabel.getText(),
                            "已完成")));
                }
            }
            default -> {
                menuLabel.setGraphic(IconUtils.getGlyph("none-process-icon"));
                menuLabel.getStyleClass().add("none-process");
                if (Objects.nonNull(menuLabel.getTooltip())) {
                    menuLabel.getTooltip().setText(String.format(TOOLTIP_FORMAT, menuLabel.getTooltip().getText(),
                            "未开始"));
                } else {
                    menuLabel.setTooltip(new Tooltip(String.format(TOOLTIP_FORMAT, menuLabel.getText(),
                            "未开始")));
                }
            }
        }
    }

    public static void appendCopy(Label label, CommonCallback onSuccess){
        label.setOnMouseClicked(me->{
            if(me.getButton().equals(MouseButton.PRIMARY) && me.getClickCount() == DOUBLE_CLICK_COUNT){
                AppUtils.copyClipboard(label.getText());
                if(Objects.nonNull(onSuccess)){
                    onSuccess.action();
                }
            }
        });
    }

    public static void appendCopy(VBox vBox, CommonCallback onSuccess) {
        vBox.setOnMouseClicked(me -> {
            if (me.getButton().equals(MouseButton.PRIMARY) && me.getClickCount() == DOUBLE_CLICK_COUNT) {
                String content = vBox.getChildren()
                        .stream()
                        .filter(n -> n instanceof Label)
                        .map(n -> ((Label) n).getText())
                        .filter(StringUtils::isNotBlank)
                        .collect(Collectors.joining(BaseConstants.NEW_LINE));
                AppUtils.copyClipboard(content);
                if(Objects.nonNull(onSuccess)){
                    onSuccess.action();
                }
            }
        });
    }

    public static void renderFinishProcess(Label label, FinishState finishState) {
        label.getStyleClass().removeAll("incomplete-process", "finish-process", "none-process");
        switch (finishState) {
            case INCOMPLETE -> label.getStyleClass().add("incomplete-process");
            case FINISH -> label.getStyleClass().add("finish-process");
            default -> label.getStyleClass().add("none-process");
        }
    }

    public static Separator generateSeparator(Orientation orientation){
        var sep1 = new Separator();
        sep1.setOrientation(orientation);
        sep1.getStyleClass().add("tab-option-split");
        return sep1;
    }

    public static void initEmptyImageView(ImageView emptyImageView, Logger log){
        ClassPathResource emptyImageResource = new ClassPathResource("images/evaluation/empty.png");
        try {
            emptyImageView.setImage(new Image(emptyImageResource.getInputStream()));
        }catch (Exception ex){
            log.error("加载空图片失败",ex);
        }
    }

    public static Integer toInteger(TextField txt, String errorInfo) throws Exception{
        try{
            return Integer.parseInt(txt.getText());
        }catch (NumberFormatException ignore){
            txt.requestFocus();
            throw new Exception(errorInfo);
        }
    }

    public static String getEvaluationWindowTitle(String systemName){
        if(StringUtils.isBlank(systemName)){
            return String.format(AppConstants.EVALUATION_WIN_TITLE_FORMAT,"被测系统");
        }
        if(systemName.length()>EVALUATION_WIN_TITLE_MAX_LENGTH){
            return String.format(AppConstants.EVALUATION_WIN_TITLE_FORMAT,
                    StringUtils.substring(systemName,0,EVALUATION_WIN_TITLE_MAX_LENGTH).concat("..."));
        }else{
            return String.format(AppConstants.EVALUATION_WIN_TITLE_FORMAT,systemName);
        }
    }

    public static String getEvaluationWindowTitle(String systemName,String modelName){
        //判断阶段参数是否为空
        if(StringUtils.isBlank(modelName)){
            //测评主界面标题（密评+系统名）
            return getEvaluationWindowTitle(systemName);
        }else{
            //具体测评界面标题（密评+系统名+（阶段名））
            return String.format("%s（%s）",getEvaluationWindowTitle(systemName),modelName);
        }
    }

    public static String finishStateToIcon(FinishState state){
        return switch (state) {
            case INCOMPLETE -> "incomplete-process-icon";
            case FINISH -> "finish-process-icon";
            default -> "none-process-icon";
        };
    }

    public static List<FileChooser.ExtensionFilter> getImageExtensionFilters() {
        return Arrays.asList(new FileChooser.ExtensionFilter("图像文件", "*.png", "*.jpg", "*.jpeg",
                        "*.jpe", "*.jfif", "*.gif", "*.dib", "*.bmp", "*.tif", "*.tiff"),
                new FileChooser.ExtensionFilter("PNG", "*.png"),
                new FileChooser.ExtensionFilter("JPEG", "*.jpg", "*.jpeg", "*.jpe", "*.jfif"),
                new FileChooser.ExtensionFilter("GIF", "*.gif", "*.dib"),
                new FileChooser.ExtensionFilter("位图文件", "*.bmp", "*.dib"),
                new FileChooser.ExtensionFilter("TIFF", "*.tif", "*.tiff"));
    }

    public static SizeDTO getPhotoSize(Image photoImage, int maxWidth, int maxHeight) {
        if (photoImage.getWidth() > maxWidth
                && photoImage.getHeight() > maxHeight) {
            int narrowImgW = maxWidth;
            int narrowImgH = (int) (((float) narrowImgW / photoImage.getWidth()) * photoImage.getHeight());
            if (narrowImgH > maxHeight) {
                narrowImgW = (int) (((float) maxHeight / narrowImgH) * narrowImgW);
                narrowImgH = maxHeight;
            }
            return new SizeDTO(narrowImgW, narrowImgH);
        } else if (photoImage.getWidth() > maxWidth) {
            int narrowImgH = (int) (((float) maxWidth / photoImage.getWidth()) * photoImage.getHeight());
            return new SizeDTO(maxWidth, narrowImgH);
        } else if (photoImage.getHeight() > maxHeight) {
            int narrowImgW = (int) (((float) maxHeight / photoImage.getHeight()) * photoImage.getWidth());
            return new SizeDTO(narrowImgW, maxHeight);
        } else {
            return new SizeDTO((int) photoImage.getWidth(),
                    (int) photoImage.getHeight());
        }
    }

    public static void refreshScoreInfo(String systemId){
        var scoreView = AppStore.getEvaluationView(systemId, ScoreInfoView.class);
        if(scoreView.getController() instanceof ScoreInfoController controller){
            controller.refreshScore();
        }
    }

}